\CUSProvideExplModule{package}{\cus@d@te}{\cus@versi@n}{package loading}

\exp_args:NNo \cs_new_protected:Npn \__cus_package_if_loaded:nTF 
  { \@ifpackageloaded }
\cs_new_protected:Npn \__cus_package_if_loaded:nT #1#2 
  { \__cus_package_if_loaded:nTF {#1} {#2} { } }
\cs_new_protected:Npn \__cus_package_if_loaded:nF #1#2 
  { \__cus_package_if_loaded:nTF {#1} { } {#2} }
\exp_args:NNo \cs_new_protected:Npn \__cus_package_if_loaded_with:nnTF 
  { \@ifpackagewith }


\NewDocumentCommand \ImportPackage { s +O{} }
  {
    \cus_package_import:n {#2}
    \IfBooleanT {#1} { \cus_package_immediate: }
  }
% \DeclareDocumentCommand \RequirePackage { O{} m O{} }
%   { \clist_map_tokens:nn {#2} { \cus_package_import:nnn {#3} {#1} } }
% \cs_set_eq:NN \usepackage \RequirePackage


\cs_new_protected:Npn \cus_package_import:n % package list 
  {
    \keyval_parse:nnn 
      { \cus_twiddle_N:nnn \__cus_package_import_aux:nn { } }
      { \__cus_package_import_aux:nn }
  }
\cs_new_protected:Npn \cus_package_import:nnn #1#2#3 % release, options, package
  { \__cus_package_import_aux:nn { {#3} [#1] } {#2} }
\cs_new:Npn \cus_package_if_toload:nTF #1
  { \tl_if_exist:cTF { g__cus_package_buffer_#1_tl } }
\cs_new:Npn \cus_package_if_toload:nT #1#2 { \cus_package_if_toload:nTF {#1} {#2} { } }
\cs_new:Npn \cus_package_if_toload:nF #1#2 { \cus_package_if_toload:nTF {#1} { } {#2} }
\cs_new:Npn \__cus_package_import_aux:nn #1#2 % package, options 
  {
    \use:e { \exp_not:N \__cus_package_name_release:w \cus_split_bracket_tail:n {#1} }
    \tl_if_head_eq_meaning:nNTF {#2} [ % ]
      { \__cus_package_release_options:w #2 \s__cus_stop }
      { \tl_set:Nn \l__cus_package_options_tl {#2} }
    \cus_package_if_toload:nF \l__cus_package_name_tl 
      {
        \seq_gput_right:No \g__cus_package_buffer_seq \l__cus_package_name_tl
        \tl_gset:cx { g__cus_package_buffer_ \l__cus_package_name_tl _tl } 
          {
            { \exp_not:o \l__cus_package_release_tl }
            { \exp_not:o \l__cus_package_options_tl }
          }
      }
  }
\cs_new:Npn \__cus_package_name_release:w #1 [#2]
  {
    \tl_set:Nx \l__cus_package_name_tl { #1 }
    \tl_set:Nx \l__cus_package_release_tl { #2 }
  }
\cs_new:Npn \__cus_package_release_options:w [#1] #2 \s__cus_stop
  {
    \tl_set:Nx \l__cus_package_release_tl { #1 }
    \tl_set:Nn \l__cus_package_options_tl { #2 }
  }
\cs_new_protected:Npn \__cus_package_require:n #1
  {
    \cus_package_if_toload:nT {#1}
      { 
        \exp_last_unbraced:Nf 
          \cus_package_require:nnn { \tl_use:c { g__cus_package_buffer_#1_tl } } {#1}
      }
  }

\cs_new_protected:Npn \cus_package_rule:n #1
  { 
    \group_begin:
    \__cus_package_rule_set_special:
    \clist_map_function:nn {#1} \__cus_package_rule_aux:n 
    \group_end:
  }
\cs_new:Npn \__cus_package_rule_aux:n #1
  { 
    \exp_last_unbraced:Ne \__cus_package_rule_aux:w 
      {#1} \s_stop \s_stop \s_stop \s__cus_stop 
  }
\cs_new:Npn \__cus_package_rule_aux:w #1 \s_stop #2 \s_stop #3 \s_stop #4 \s__cus_stop
  { 
    \exp_last_unbraced:Ne \cus_package_rule:nnn 
      {
        \tl_trim_spaces:n { {#1} } 
        {#2} 
        \tl_trim_spaces:n { {#3} } 
      }
  }
\cs_new_protected:Npn \__cus_package_rule_set_special:
  {
    \cs_set:Npn \< { \s_stop before               \s_stop }
    \cs_set:Npn \> { \s_stop after                \s_stop }
    \cs_set:Npn \! { \s_stop incompatible-warning \s_stop }
    \cs_set:Npn \x { \s_stop incompatible-error   \s_stop }
    \cs_set:Npn \~ { \s_stop incompatible-ignore  \s_stop }
    \cs_set:Npn \= { \s_stop voids                \s_stop }
    \cs_set:Npn \? { \s_stop unrelated            \s_stop }
    \cs_set:Npn \& { \s_stop require              \s_stop }
    \cs_set:Npn \+ { \s_stop call                 \s_stop }
    \cs_set:Npn \| { \s_stop or                   \s_stop }
  }
\cs_new_protected:Npn \cus_package_rule:nnn #1#2#3
  {
    \cs_if_exist:cTF { __cus_package_rule_ #2 _gset:nn }
      { \use:c { __cus_package_rule_ #2 _gset:nn } {#1} {#3} }
      { \msg_warning:nnx { cus } { package-rule-unknown } {#2} }
  }

\cs_new_protected:Npn \__cus_package_rule_before_gset:nn #1#2 { }
\cs_new_eq:cN { __cus_package_rule_<_gset:nn } \__cus_package_rule_before_gset:nn
\cs_new_protected:Npn \__cus_package_rule_after_gset:nn #1#2 { }
\cs_new_eq:cN { __cus_package_rule_>_gset:nn } \__cus_package_rule_after_gset:nn
\cs_new_protected:cpn { __cus_package_rule_ incompatible-warning _gset:nn } #1#2 { }
\cs_new_eq:cc { __cus_package_rule_!_gset:nn }
  { __cus_package_rule_ incompatible-warning _gset:nn } 
\cs_new_protected:cpn { __cus_package_rule_ incompatible-error _gset:nn } #1#2 { }
\cs_new_eq:cc { __cus_package_rule_x_gset:nn }
  { __cus_package_rule_ incompatible-error _gset:nn } 
\cs_new_protected:cpn { __cus_package_rule_ incompatible-ignore _gset:nn } #1#2 { }
\cs_new_eq:cc { __cus_package_rule_ \c_tilde_str _gset:nn }
  { __cus_package_rule_ incompatible-ignore _gset:nn } 
\cs_new_protected:Npn \__cus_package_rule_voids_gset:nn #1#2 { }
\cs_new_eq:cN { __cus_package_rule_=_gset:nn } \__cus_package_rule_voids_gset:nn
\cs_new_protected:Npn \__cus_package_rule_unrelated_gset:nn #1#2 { }
\cs_new_eq:cN { __cus_package_rule_?_gset:nn } \__cus_package_rule_unrelated_gset:nn 
\cs_new_protected:Npn \__cus_package_rule_require_gset:nn #1#2 { }
\cs_new_eq:cN { __cus_package_rule_&_gset:nn } \__cus_package_rule_require_gset:nn
\cs_new_protected:Npn \__cus_package_rule_call_gset:nn #1#2 { }
\cs_new_eq:cN { __cus_package_rule_+_gset:nn } \__cus_package_rule_call_gset:nn
\cs_new_protected:Npn \__cus_package_rule_or_gset:nn #1#2 { }
\cs_new_eq:cN { __cus_package_rule_|_gset:nn } \__cus_package_rule_or_gset:nn 


\int_const:Nn \c__cus_package_rule_unrelated_int { 0 }
\int_const:Nn \c__cus_package_rule_xW_int { 1 } % incompatible-warning
\int_const:Nn \c__cus_package_rule_xE_int { 2 } % incompatible-error
\int_const:Nn \c__cus_package_rule_xI_int { 3 } % incompatible-ignore
\int_const:Nn \c__cus_package_rule_voids_int { 4 }
\int_const:Nn \c__cus_package_rule_require_int { 5 }
\int_const:Nn \c__cus_package_rule_call_int { 6 }
\int_const:Nn \c__cus_package_rule_or_int { 7 }
\int_const:Nn \c__cus_package_rule_ordered_int { 8 }
\cs_new:Npn \__cus_package_if_related:nnTF #1#2
  {
    \bool_lazy_and:nnTF
      { \cs_if_exist_p:c { l__cus_package_rule_#1|#2_int } }
      { \int_compare_p:nNn { \use:c { l__cus_package_rule_#1|#2_int } } > \c_zero_int }
  }
\cs_new:Npn \__cus_package_if_ordered:nn 


\hook_new:n { cus/__package_rule }
\tl_new:N \g__cus_package_code_tl 
\hook_gput_code:nnn {begindocument/before} {cus/document} 
  { \cus_package_immediate: }
\cs_new_protected:Npn \cus_package_immediate:
  {
    %\seq_map_function:NN \g__cus_package_buffer_seq
    \hook_use:n { cus/__package_rule }
    %\tl_use:N \g__cus_package_code_tl
    %\tl_gclear:N \g__cus_package_code_tl
    \seq_gclear:N \g__cus_package_buffer_seq 
  }
%\cs_new_protected:Npn \cus_gput_package_code:n 
%  { \tl_gput_right:Nn \g__cus_package_code_tl }



% release, options, package 
\cs_new_protected:Npn \cus_package_require:nnn #1#2#3
  { \@onefilewithoptions {#3} [{#2}] [{#1}] \@pkgextension } % still keep hooks 
\hook_gput_code:nnn {begindocument/before} {cus/document} 
  {
    \cs_gset_protected:Npn \cus_package_require:nnn #1#2#3 
      { \msg_warning:nnn { cus } { package-require-preamble } {#3} }
  }


\msg_new:nnn { cus } { package-rule-unknown } { Unknown~package~rule:~`#1'. }
\msg_new:nnn { cus } { package-require-preamble }
  { You~cannot~load~package~`#1'~after~preamble. }

\endinput 

<  before                 1在2之前加载
>  after                  1在2之后加载
!  incompatible-warning   1与2不兼容，警告，如果某一个加载了则后一个不加载，可以为空
x  incompatible-error     1与2不兼容，报错，如果某一个加载了则后一个不加载，可以为空
~  incompatible-ignore    1与2不兼容，忽略，如果某一个加载了则后一个不加载，可以为空
=  voids / overwrite      如果要加载2，则替换为1
?  unrelated              不相关或未定义
&  require                1加载时在它之前加载2
+  call                   1加载完之后立即加载2
|  or                     1，2可平替

